package cn.iocoder.yudao.module.system.service.roleaccess;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.enums.roleaccess.RequestMethodEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.system.controller.admin.roleaccess.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.roleaccess.RoleAccessDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.system.dal.mysql.roleaccess.RoleAccessMapper;
import org.springframework.web.bind.annotation.RequestMethod;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 角色和APIJSON权限关联 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class RoleAccessServiceImpl implements RoleAccessService {

    @Resource
    private RoleAccessMapper roleAccessMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Override
    public Long createRoleAccess(RoleAccessSaveReqVO createReqVO) {
        // 插入
        RoleAccessDO roleAccess = BeanUtils.toBean(createReqVO, RoleAccessDO.class);
        roleAccessMapper.insert(roleAccess);
        // 返回
        return roleAccess.getId();
    }

    @Override
    public void updateRoleAccess(RoleAccessSaveReqVO updateReqVO) {
        // 校验存在
        validateRoleAccessExists(updateReqVO.getId());
        // 更新
        RoleAccessDO updateObj = BeanUtils.toBean(updateReqVO, RoleAccessDO.class);
        roleAccessMapper.updateById(updateObj);
    }

    @Override
    public void deleteRoleAccess(Long id) {
        // 校验存在
        validateRoleAccessExists(id);
        // 删除
        roleAccessMapper.deleteById(id);
    }

    @Override
    public void deleteRoleAccessListByIds(List<Long> ids) {
        // 校验存在
        validateRoleAccessExists(ids);
        // 删除
        roleAccessMapper.deleteByIds(ids);
    }

    private void validateRoleAccessExists(List<Long> ids) {
        List<RoleAccessDO> list = roleAccessMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ROLE_ACCESS_NOT_EXISTS);
        }
    }

    private void validateRoleAccessExists(Long id) {
        if (roleAccessMapper.selectById(id) == null) {
            throw exception(ROLE_ACCESS_NOT_EXISTS);
        }
    }

    @Override
    public RoleAccessDO getRoleAccess(Long id) {
        return roleAccessMapper.selectById(id);
    }

    @Override
    public PageResult<RoleAccessDO> getRoleAccessPage(RoleAccessPageReqVO pageReqVO) {
        return roleAccessMapper.selectPage(pageReqVO);
    }

    public List<RoleAccessDO> getRoleAccessListByUserId(Long userId) {
        LambdaQueryWrapper<UserRoleDO> userRoleDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userRoleDOLambdaQueryWrapper.eq(UserRoleDO::getUserId, userId);
        List<UserRoleDO> userRoleDOList = userRoleMapper.selectList(userRoleDOLambdaQueryWrapper);
        List<Long> roleIds = userRoleDOList.stream().map(UserRoleDO::getRoleId).collect(Collectors.toList());
        LambdaQueryWrapper<RoleAccessDO> roleAccessDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleAccessDOLambdaQueryWrapper.in(RoleAccessDO::getRoleId, roleIds)
                .select(RoleAccessDO::getId, RoleAccessDO::getRoleId, RoleAccessDO::getAlias, RoleAccessDO::getMethod);
        return roleAccessMapper.selectList(roleAccessDOLambdaQueryWrapper);
    }

    @Override
    public List<RoleAccessDO> getRoleAccessListByRoleId(RoleAccessRoleReqVO roleAccessRoleReqVO) {
        return roleAccessMapper.selectList(new LambdaQueryWrapper<RoleAccessDO>().eq(RoleAccessDO::getRoleId, roleAccessRoleReqVO.getRoleId()));
    }

    @Override
    @Transactional
    public void addRoleAccess(RoleAccessAddReqVO roleAccessAddReqVO) {
        //删除当前角色全部权限
        QueryWrapper<RoleAccessDO> roleAccessDOQueryWrapper = new QueryWrapper<>();
        roleAccessDOQueryWrapper.lambda().eq(RoleAccessDO::getRoleId, roleAccessAddReqVO.getRoleId());
        roleAccessMapper.delete(roleAccessDOQueryWrapper);
        //添加校色权限
        List<AccessAllDataReqVO> allDataReqVOList = roleAccessAddReqVO.getAccessAllDataReqVOList();

        List<RoleAccessDO> saveList = new ArrayList<>();
        allDataReqVOList.forEach(accessAllDataReqVO -> {
            saveList.addAll(getRoleAccessDOByAccessAllDataReqVO(accessAllDataReqVO, roleAccessAddReqVO.getRoleId()));
        });
        roleAccessMapper.insertBatch(saveList);
    }

    private List<RoleAccessDO> getRoleAccessDOByAccessAllDataReqVO(AccessAllDataReqVO accessAllDataReqVO, Long roleId) {
        List<RoleAccessDO> saveList = new ArrayList<>();
        if (accessAllDataReqVO.getGet()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.GET.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getPost()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.POST.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getPut()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.PUT.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getDelete()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.DELETE.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getCrud()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.CRUD.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getGets()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.GETS.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getHeads()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.HEADS.name());
            saveList.add(data);
        }
        if (accessAllDataReqVO.getHead()) {
            RoleAccessDO data = new RoleAccessDO();
            data.setRoleId(roleId);
            data.setAlias(accessAllDataReqVO.getAlias());
            data.setMethod(RequestMethodEnum.HEAD.name());
            saveList.add(data);
        }
        return saveList;
    }


}